#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cassert>

using namespace std;

void PrintSig(sigset_t &pending)
{
    cout << "Pending bitmap : ";
    // 穷举所有的信号编号，然后再一一判断是否在pending表里
    // 我们要使得最左边是最高位2^31, 2^30, 2^29, ... , 2^1 所以从31号信号开始判断并打印
    for (int signo = 31; signo > 0; signo--)
    {
        if (sigismember(&pending, signo))
        {
            cout << "1";
        }
        else
        {
            cout << "0";
        }
    }
    cout << endl;
}

void hander(int signo)
{
    sigset_t pending;
    sigemptyset(&pending);

    int n = sigpending(&pending);
    assert(n == 0);
    cout << "递达中... : ";
    PrintSig(pending);
    cout << signo << "号信号被抵达处理..." << endl;
}

int main()
{
    // 自定义信号处理方法
    // signal(2, hander);

    cout << "pid : " << getpid() << endl;

    // 1、屏蔽2号信号
    sigset_t block, oblock; // sigset_t 是一个操作系统提供的类型，与语言无关。
    sigemptyset(&block);
    sigemptyset(&oblock);
    sigaddset(&block, 2); // 以上都没有涉及内核，只是在对sigset_t做设置

    // 经过实验证明，不会出现一个金刚不坏的进程，因为9号和19号信号，是无法被屏蔽的
    // 0. for test: 如果我屏蔽了所有信号呢？？？
    // for(int signo = 1; signo <= 31; signo++) // 9， 19号信号无法被屏蔽， 18号信号会被做特殊处理
    //     sigaddset(&block, signo); // SIGINT --- 根本就没有设置进当前进程的PCB block位图中

    // 1.1 开始屏蔽2号信号，其实就是设置进入内核中

    // SIG_BLOCK         //增加屏蔽字信号
    // SIG_UNBLOCK       //解除屏蔽字信号
    // SIG_SETMASK       //覆盖式写入屏蔽字信号
    int n = sigprocmask(SIG_BLOCK, &block, &oblock);
    assert(n == 0);
    // (void)n; // 骗过编译器，不要告警，因为我们后面用了n，不光光是定义
    cout << "block 2 signal success" << endl;

    int cnt = 0;
    while (true)
    {
        // 2. 获取进程的pending位图
        sigset_t pending;
        sigemptyset(&pending);
        n = sigpending(&pending);
        assert(n == 0);

        // 3. 打印pending位图中的收到的信号
        PrintSig(pending);
        cnt++;
        sleep(1);

        // // 4. 解除对2号信号的屏蔽
        // if (cnt == 20)
        // {
        //     cout << "解除对2号信号的屏蔽" << endl;
        //     n = sigprocmask(SIG_UNBLOCK, &block, &oblock);
        //     // 我还想看到pending 2号信号 1->0 : 递达二号信号！
        //     assert(n == 0);
        // }
    }

    sleep(1);
    return 0;
}

// int main()
// {

//     pid_t id = fork();

//     if (id == 0)
//     {
//         // child
//         int a = 10;
//         a /= 0;
//         exit(0);
//     }
//     // father
//     int status = 0;
//     pid_t rid = waitpid(id, &status, 0);
//     if(rid > 0)
//     {
//         std::cout << "exit code: " << ((status>>8) & 0xFF) << std::endl;
//         std::cout << "exit signal: " << (status & 0x7F) << std::endl;
//         std::cout << "exit dump: " << ((status>>7) & 0x1) << std::endl;
//     }

//     return 0;
// }

// int main()
// {
//     std::cout << "run begin ..." << std::endl;
//     int a = 10;
//     a /= 0;
//     std::cout << "run end ..." << std::endl;

//     while(true) sleep(1);
//     return 0;
// }
